package com.myk.game.gobangchess.ai.symmetric;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 该文件实现了棋子分布均匀度的计算函数。
 * 后续使用者可以通过调用 UniformityScorer.calculateUniformity() 来获取分数。
 */
public class UniformityScorer {

    /**
     * 计算并返回黑白双方棋子的均匀度分数。
     * 均匀度通过对棋盘进行多种方式的分块，计算各分块内棋子数量的方差来衡量。
     * 方差越小，分布越均匀，分数越高（分数为加权方差的相反数）。
     *
     * @param board 15x15 的棋盘矩阵。1为黑棋，-1为白棋，0为空位。
     *              格式: int[15][15]
     * @param coefficients 一个包含4个元素的double数组，用于对不同分块方式的方差进行加权。
     *                     - coefficients[0]: 3x3大块 (每块5x5) 的权重 (系数1)
     *                     - coefficients[1]: 5x5大块 (每块3x3) 的权重 (系数2)
     *                     - coefficients[2]: 行和列分块的权重 (系数3)
     *                     - coefficients[3]: 正斜向和反斜向分块的权重 (系数4)
     *                     推荐的默认值为 {1.0, 1.0, 1.0, 1.0}。
     *                     格式: double[4]
     * @return 一个包含两个元素的double数组，[0]为黑棋的均匀度分数，[1]为白棋的均匀度分数。
     *         格式: double[2]
     */
    public static double[] calculateUniformity(int[][] board, double[] coefficients) {
        double blackScore = calculateForColor(board, 1, coefficients);
        double whiteScore = calculateForColor(board, -1, coefficients);
        return new double[]{blackScore, whiteScore};
    }

    /**
     * 为指定颜色的棋子计算均匀度分数。
     */
    private static double calculateForColor(int[][] board, int color, double[] coefficients) {
        final int BOARD_SIZE = 15;
        List<Double> variances = new ArrayList<>();

        // 1. 3x3大块 (每块5x5)
        List<Integer> counts1 = new ArrayList<>();
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                int count = 0;
                for (int r = i * 5; r < (i + 1) * 5; r++) {
                    for (int c = j * 5; c < (j + 1) * 5; c++) {
                        if (board[r][c] == color) count++;
                    }
                }
                counts1.add(count);
            }
        }
        variances.add(calculateVariance(counts1));

        // 2. 5x5大块 (每块3x3)
        List<Integer> counts2 = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            for (int j = 0; j < 5; j++) {
                int count = 0;
                for (int r = i * 3; r < (i + 1) * 3; r++) {
                    for (int c = j * 3; c < (j + 1) * 3; c++) {
                        if (board[r][c] == color) count++;
                    }
                }
                counts2.add(count);
            }
        }
        variances.add(calculateVariance(counts2));

        // 3. 按列分块 (15列)
        List<Integer> counts3 = new ArrayList<>();
        for (int c = 0; c < BOARD_SIZE; c++) {
            int count = 0;
            for (int r = 0; r < BOARD_SIZE; r++) {
                if (board[r][c] == color) count++;
            }
            counts3.add(count);
        }
        variances.add(calculateVariance(counts3));

        // 4. 按行分块 (15行)
        List<Integer> counts4 = new ArrayList<>();
        for (int r = 0; r < BOARD_SIZE; r++) {
            int count = 0;
            for (int c = 0; c < BOARD_SIZE; c++) {
                if (board[r][c] == color) count++;
            }
            counts4.add(count);
        }
        variances.add(calculateVariance(counts4));

        // 5. 按正斜向分块 (29条)
        List<Integer> counts5 = new ArrayList<>();
        for (int k = -(BOARD_SIZE - 1); k < BOARD_SIZE; k++) { // k = r - c, from -14 to 14
            int count = 0;
            for (int r = 0; r < BOARD_SIZE; r++) {
                int c = r - k;
                if (c >= 0 && c < BOARD_SIZE) {
                    if (board[r][c] == color) count++;
                }
            }
            counts5.add(count);
        }
        variances.add(calculateVariance(counts5));

        // 6. 按反斜向分块 (29条)
        List<Integer> counts6 = new ArrayList<>();
        for (int k = 0; k < 2 * BOARD_SIZE - 1; k++) { // k = r + c, from 0 to 28
            int count = 0;
            for (int r = 0; r < BOARD_SIZE; r++) {
                int c = k - r;
                if (c >= 0 && c < BOARD_SIZE) {
                    if (board[r][c] == color) count++;
                }
            }
            counts6.add(count);
        }
        variances.add(calculateVariance(counts6));

        // 加权求和
        double score = 0.0;
        score += -variances.get(0) * coefficients[0]; // 系数1
        score += -variances.get(1) * coefficients[1]; // 系数2
        score += -variances.get(2) * coefficients[2]; // 系数3 (列)
        score += -variances.get(3) * coefficients[2]; // 系数3 (行)
        score += -variances.get(4) * coefficients[3]; // 系数4 (正斜)
        score += -variances.get(5) * coefficients[3]; // 系数4 (反斜)

        return score;
    }

    /**
     * 计算一组计数的方差。
     */
    private static double calculateVariance(List<Integer> counts) {
        if (counts == null || counts.isEmpty()) {
            return 0.0;
        }
        double sum = 0.0;
        for (int count : counts) {
            sum += count;
        }
        double mean = sum / counts.size();
        double squaredDifferenceSum = 0.0;
        for (int count : counts) {
            squaredDifferenceSum += (count - mean) * (count - mean);
        }
        return squaredDifferenceSum / counts.size();
    }

    /**
     * 用于验证和展示函数功能的 main 方法。
     */
    public static void main(String[] args) {
        // 1. 定义一个显式的15x15测试棋盘
        // 黑棋聚集在左上角 (高方差, 低均匀度, 分数低)
        // 白棋分散在棋盘各处 (低方差, 高均匀度, 分数高)
        int[][] board = new int[15][15];
        board[0][0] = 1; board[0][1] = 1; board[0][2] = 1;
        board[1][0] = 1; board[1][1] = 1; board[1][2] = 1;
        board[2][0] = 1; board[2][1] = 1; board[2][2] = 1;

        board[5][5] = -1; board[7][10] = -1; board[12][3] = -1;
        board[14][14] = -1; board[0][14] = -1; board[14][0] = -1;
        board[3][8] = -1; board[8][3] = -1; board[10][12] = -1;

        // 2. 打印测试棋盘 (假设 BoardPrinter 类可用)
        System.out.println("--- Test Board ---");
        BoardPrinter.printBoardWithIndices(board);
        System.out.println();

        // 3. 定义输入参数
        double[] coefficients = {1.0, 2.0, 3.0, 4.0};
        System.out.println("--- Input ---");
        System.out.println("Board: (shown above)");
        System.out.println("Coefficients: " + Arrays.toString(coefficients));
        System.out.println();

        // 4. 调用函数进行计算
        double[] scores = calculateUniformity(board, coefficients);

        // 5. 打印详细输出
        System.out.println("--- Output ---");
        System.out.printf("Black Player Uniformity Score: %.4f%n", scores[0]);
        System.out.printf("White Player Uniformity Score: %.4f%n", scores[1]);
        System.out.println();
        System.out.println("Note: A higher score (closer to 0) indicates better uniformity.");
        System.out.println("As expected, the scattered white pieces get a much higher (better) score than the clustered black pieces.");
    }
}